#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>

#include "Common.hpp"
#include "Log.hpp"
const std::string Sep = "\r\n";
const std::string LineSep = " ";
const std::string HeaderLineSep = ": ";
const std::string BlankLine = Sep;
const std::string defaulthomepage = "wwwroot";
const std::string HttpVersion = "HTTP/1.0";
const std::string page404 = "wwwroot/404.html";
const std::string firstpage = "index.html";

using namespace LogMudule;
// B/S
class HttpRequest
{
public:
    HttpRequest() {}
    ~HttpRequest() {}
    
    // Host: 120.46.155.207:8080
    // Connection: keep-alive
    // Cache-Control: max-age=0
    // 解析头部kv
    void ParseHeaderKv()
    {
        std::string key, value;
        for (auto &rep_header : _req_header)
        {
            if (SplitString(rep_header, HeaderLineSep, &key, &value))
            {
                _headerkv[key] = value;
            }
        }
    }
    // 解析报头
    bool ParseHeader(std::string &request_str)
    {
        std::string line;
        while (true)
        {
            // 解析请求行
            bool r = ParseOneLine(request_str, &line, Sep);
            if (r && !line.empty())
            {
                _req_header.push_back(line);
            }
            else if (r && line.empty())
            {
                _blank_line = Sep;
                break;
            }
            else
            {
                return false;
            }
        }
        ParseHeaderKv();
        return true;
    }

    // GET / HTTP/1.1
    // Host: 120.46.155.207:8080
    // Connection: keep-alive
    // Cache-Control: max-age=0
    // Upgrade-Insecure-Requests: 1
    // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0
    // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
    // Accept-Encoding: gzip, deflate
    // Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
    //
    void Deserialize(std::string &request_str)
    {
        LOG(LogLevel::DEBUG) << "开始进入:Deserialize";
        if (ParseOneLine(request_str, &_req_line, Sep))
        {
            ParseReqLine(_req_line, LineSep);
            ParseHeader(request_str);
            _req_body = request_str;
        }

        // 分析请求中，是否含有参数
        if(_method == "POST")
        {
            _isexec = true; // 参数在正文中
            _args = _req_body; // 正文中就是参数
            _path = _uri; // 路径就是uri
            LOG(LogLevel::DEBUG) << "POST: _path: " << _path;
            LOG(LogLevel::DEBUG) << "POST: _args: " << _args;
        }
        else if(_method == "GET")
        {
            auto pos = _uri.find('?');
            if(pos != std::string::npos)
            {
                _isexec = true;
                // login?name=zxw&pwd=123456
                _path = _uri.substr(0, pos); // 键
                _args = _uri.substr(pos + 1); // 值
                LOG(LogLevel::DEBUG) << "GET: _path: " << _path;
                LOG(LogLevel::DEBUG) << "GET: _args: " << _args;
            }
        }
    }

    void Print()
    {
        std::cout << "_method: " << _method << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_version: " << _version << std::endl;

        for (auto &kv : _headerkv)
        {
            std::cout << kv.first << " # " << kv.second << std::endl;
        }
        std::cout << "_blank_line: " << _blank_line << std::endl;
        std::cout << "_body: " << _req_body << std::endl;
    }

    std::string GetContent(const std::string &path)
    {
        std::string content;
        std::ifstream in(path, std::ios::binary);
        if(!in.is_open())
            return std::string();
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        LOG(LogLevel::DEBUG) << "GetContent success, " <<"content length: " << content.size();
        return content;
    }

    bool IsHasArgs()
    {
        return _isexec;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Args()
    {
        return _args;
    }
    std::string Uri()
    {
        return _uri;
    }

    void SetUri(const std::string newuri)
    {
        _uri = newuri;
    }

    // 获得后缀名
    std::string Suffix()
    {
        // _uri -> wwwroot/index.html
        auto pos = _uri.rfind('.');
        if (pos == std::string::npos)
        {
            return std::string(".html");
        }
        else
        {
            return _uri.substr(pos);
        }
    }

private:
    // 解析请求行
    void ParseReqLine(const std::string &req_line, const std::string &sep)
    {
        std::stringstream ss(_req_line);
        ss >> _method >> _uri >> _version;
    }

private:
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _blank_line;
    std::string _req_body;

    // 反序列化的过程中，细化我们解析出来的字段
    std::string _method;
    std::string _uri;
    std::string _path;
    std::string _args;
    std::string _version;
    std::unordered_map<std::string, std::string> _headerkv;

    bool _isexec = false;

};

class HttpResponse
{
public:
    HttpResponse()
        : _verion(HttpVersion), _blank_line(Sep)
    {
    }
    ~HttpResponse() {}

    // HTTP/1.1 200 OK
    // Content-Length: 88
    // Content-Type: text/html;charset=UTF-8
    // Content-Language: zh-CN
    // Transfer-Encoding: chunked
    // Date: Fri, 29 Sep 2017 05:10:13 GMT
    void Build(HttpRequest &req)
    {
// #define TestRedir 1
// #ifdef TestRedir
//         _status_code = 302;
//         _status_desc = Code2Desc(_status_code);
//         SetHeader("Location", "https://www.baidu.com/");
//         for (auto &header : _headerkv)
//         {
//             _resp_header.push_back(header.first + HeaderLineSep + header.second);
//         }
// #else
        std::string uri = defaulthomepage + req.Uri(); // wwwroot/

        if (uri.back() == '/')
        {
            uri += firstpage; // wwwroot/index.html
            req.SetUri(uri);
        }
        LOG(LogLevel::DEBUG) << "客户端请求 -----> URI：" << uri;

        _content = req.GetContent(uri);
        if (_content.empty())
        {
            // 404
            _status_code = 404;
            req.SetUri(page404);
            _content = req.GetContent(uri);
        }
        else
        {
            _status_code = 200;
        }
        _status_desc = Code2Desc(_status_code);


        if (!_content.empty())
        {
            SetHeader("Content-Length", std::to_string(_content.size()));
        }
        
        std::string mime_type = Suffix2Desc(req.Suffix());
        SetHeader("Content-Type", mime_type);

        _resp_body = _content;
        //req.Print();
// #endif
    }


    // 序列化
    void Serialize(std::string *resp_str)
    {
        for (auto &header : _headerkv)
        {
            _resp_header.push_back(header.first + HeaderLineSep + header.second);
        }

        // 请求行
        _resp_line = _verion + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep;


        // 序列化
        *resp_str = _resp_line;
        for (auto &line : _resp_header)
        {
            *resp_str += (line + Sep);
        }
        *resp_str += _blank_line + _resp_body;
    }

    void SetCode(int code)
    {
        _status_code = code;
        _status_desc = Code2Desc(_status_code);
    }
    void SetBody(const std::string &body)
    {
        _resp_body= body;
    }

    void SetHeader(const std::string &key, const std::string &value)
    {
        _headerkv[key] = value;
    }

private:
    std::string Code2Desc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        default:
            return std::string();
        }
    }

    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
        {
            return "text/html";
        }
        else if (suffix == ".jpg")
        {
            return "application/x-jpg";
        }
        else
        {
            return "text/html";
        }
    }

private:
    // 必备的要素
    std::string _verion;
    int _status_code;
    std::string _status_desc;
    std::string _content;
    std::unordered_map<std::string, std::string> _headerkv;

    // 最终要这4部分，构建应答
    std::string _resp_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _resp_body;

};
